#include <string>
#include <chrono>
#include <thread>
#include <iostream>

#include <zmq.hpp>

// zmq的router-dealer模式，router 会接收到 两 frame 的消息 ，第一帧是 发送端的 标识。第二帧才是 真正的数据。
// 同时 router 回复的时候，也要 发送两 frame
// 用来 监听 服务器 是否 tcp是否断开。

int main() {
    zmq::context_t context{1};
    std::string id = "api-gateway-01";
    zmq::socket_t socket{context, zmq::socket_type::dealer};
//    zmq::monitor_t monitor{};
//    monitor.init(socket, "inproc://monitor.rep", ZMQ_EVENT_ALL);

    socket.set(zmq::sockopt::routing_id, id);
    socket.connect("tcp://127.0.0.1:9012");
//    new std::thread([&] {
//        zmq::socket_t internalSocket{context, zmq::socket_type::pair};
//        internalSocket.connect("inproc://monitor.rep");
//        while (1) {
//            zmq::message_t request;
//            internalSocket.recv(request, zmq::recv_flags::none);
//            std::cout << "Received " << std::endl;
//        }
//
//    });

//   const zmq_pollitem_t items[] = {
//            {socket, 0, ZMQ_POLLIN | ZMQ_POLLERR | ZMQ_POLLPRI, 0},
//
//    };

    std::vector<zmq_pollitem_t> items = {{socket, 0, ZMQ_POLLIN | ZMQ_POLLERR | ZMQ_POLLPRI, 0}};


//    socket.send(zmq::buffer("hello"), zmq::send_flags::dontwait);
//    std::cout << "hand send " << std::endl;
    // zmq_socket_monitor 可以用它来对 监听 对端有没断开连接。
    for (;;) {
        int rc = zmq::poll(items, std::chrono::milliseconds{100});

        if (rc == -1) {
            break;
        }

        if (items[0].revents & ZMQ_POLLIN) {
            zmq::message_t request;
            socket.recv(request, zmq::recv_flags::none);
            std::cout << "Received " << request.to_string() << std::endl;
        }
        if (items[0].revents & ZMQ_POLLERR) {
            std::cout << items[0].revents << std::endl;
        }
        if (items[0].revents & ZMQ_POLLPRI) {
            std::cout << items[0].revents << std::endl;
        }

    }

    return 0;
}

/*

#include <stdio.h>
#include <zmq.h>
#include <pthread.h>
#include <cstring>
#include <assert.h>
#include <string.h>

static int read_msg(void *s, zmq_event_t *event, char *ep) {
    int rc;
    zmq_msg_t msg1;  // binary part
    zmq_msg_init(&msg1);
    zmq_msg_t msg2;  //  address part
    zmq_msg_init(&msg2);
    rc = zmq_msg_recv(&msg1, s, 0);
    if (rc == -1 && zmq_errno() == ETERM)
        return 1;
    assert (rc != -1);
    assert (zmq_msg_more(&msg1) != 0);
    rc = zmq_msg_recv(&msg2, s, 0);
    if (rc == -1 && zmq_errno() == ETERM)
        return 1;
    assert (rc != -1);
    assert (zmq_msg_more(&msg2) == 0);
    // copy binary data to event struct
    const char *data = (char *) zmq_msg_data(&msg1);
    memcpy(&(event->event), data, sizeof(event->event));
    memcpy(&(event->value), data + sizeof(event->event), sizeof(event->value));
    // copy address part
    const size_t len = zmq_msg_size(&msg2);
    ep = static_cast<char *>(memcpy(ep, zmq_msg_data(&msg2), len));
    *(ep + len) = 0;
    return 0;
}

// REP socket monitor thread
static void *rep_socket_monitor(void *ctx) {
    zmq_event_t event;
    static char addr[1025];
    int rc;
    printf("starting monitor...\n");
    void *s = zmq_socket(ctx, ZMQ_PAIR);
    assert (s);
    rc = zmq_connect(s, "inproc://monitor.rep");
    assert (rc == 0);
    while (!read_msg(s, &event, addr)) {
        switch (event.event) {
            case ZMQ_EVENT_LISTENING:
                printf("listening socket descriptor %d\n", event.value);
                printf("listening socket address %s\n", addr);
                break;
            case ZMQ_EVENT_ACCEPTED:
                printf("accepted socket descriptor %d\n", event.value);
                printf("accepted socket address %s\n", addr);
                break;
            case ZMQ_EVENT_CLOSE_FAILED:
                printf("socket close failure error code %d\n", event.value);
                printf("socket address %s\n", addr);
                break;
            case ZMQ_EVENT_CLOSED:
                printf("closed socket descriptor %d\n", event.value);
                printf("closed socket address %s\n", addr);
                break;
            case ZMQ_EVENT_DISCONNECTED:
                printf("disconnected socket descriptor %d\n", event.value);
                printf("disconnected socket address %s\n", addr);
                break;
            case ZMQ_EVENT_CONNECTED:
                printf("connected socket descriptor %d\n", event.value);
                printf("connected socket address %s\n", addr);
        }
    }
    zmq_close(s);
    return NULL;
}

int main() {
    const char *addr = "tcp://127.0.0.1:9012";
    pthread_t thread;
    //  Create the infrastructure
    void *ctx = zmq_init(1);
    assert (ctx);
    // REP socket
    void *rep = zmq_socket(ctx, ZMQ_DEALER);
    assert (rep);
    // REP socket monitor, all events
    int rc = zmq_socket_monitor(rep, "inproc://monitor.rep", ZMQ_EVENT_ALL);
    assert (rc == 0);
    rc = pthread_create(&thread, NULL, rep_socket_monitor, ctx);
    assert (rc == 0);
    rc = zmq_connect(rep, addr);
    assert (rc == 0);
    // Allow some time for event detection
    zmq_sleep(105);
    // Close the REP socket
    rc = zmq_close(rep);
    assert (rc == 0);
    zmq_term(ctx);
    return 0;
}
*/
